package com.gnerv.sylvanas.framework.common.model;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import lombok.Data;

import java.time.Instant;

/**
 * @author Gnerv LiGen
 */
@Data
@JsonInclude(JsonInclude.Include.NON_EMPTY)
@JsonPropertyOrder({"success", "code", "title", "detail", "instance", "data", "page", "timestamp", "version", "traceId"})
public class RestResult<T> {

    /**
     * 业务是否成功
     */
    private boolean success;

    /**
     * 业务状态码
     */
    private int code;

    /**
     * 响应消息标题，例：参数错误
     */
    private String title;

    /**
     * 响应消息详情，例：参数[ukId]不能为空。
     */
    private String detail;

    /**
     * 响应码对应示例,一般用于指定错误码说明链接地址。
     */
    private String instance;

    /**
     * 响应数据
     */
    private T data;

    /**
     * 分页信息
     */
    private RestResultPage page;

    /**
     * 时间戳
     */
    private Long timestamp;

    /**
     * 接口版本
     */
    private String version;

    /**
     * 链路追踪id
     */
    private String traceId;

    private RestResult() {
    }

    public static <T> RestResult<T> ok() {
        return build(RestResultCode.CODE_200);
    }

    public static <T> RestResult<T> created() {
        return build(RestResultCode.CODE_201);
    }

    public static <T> RestResult<T> updated() {
        return build(RestResultCode.CODE_202);
    }

    public static <T> RestResult<T> deleted() {
        return build(RestResultCode.CODE_203);
    }

    public static <T> RestResult<T> ok(T data) {
        return build(RestResultCode.CODE_200, data);
    }

    public static <T> RestResult<T> ok(RestResultCode restResultCode) {
        return build(restResultCode);
    }

    public static <T> RestResult<T> ok(RestResultCode restResultCode, T data) {
        return build(restResultCode, data);
    }

    public static <T> RestResult<T> error() {
        return build(RestResultCode.CODE_500);
    }

    public static <T> RestResult<T> error(T data) {
        return build(RestResultCode.CODE_500, data);
    }

    public static <T> RestResult<T> error(RestResultCode restResultCode) {
        return build(restResultCode);
    }

    public static <T> RestResult<T> error(RestResultCode restResultCode, String detail) {
        return build(restResultCode, detail);
    }

    public static <T> RestResult<T> error(RestResultCode restResultCode, String detail, String instance) {
        return build(restResultCode.getCode(), restResultCode.getDescription(), detail, instance, null);
    }

    public static <T> RestResult<T> error(RestResultCode restResultCode, T data) {
        return build(restResultCode.getCode(), restResultCode.getDescription(), null, null, data);
    }

    private static <T> RestResult<T> build(RestResultCode restResultCode) {
        return build(restResultCode.getCode(), restResultCode.getDescription(), null, null, null);
    }

    private static <T> RestResult<T> build(RestResultCode restResultCode, String detail) {
        return build(restResultCode.getCode(), restResultCode.getDescription(), detail, null, null);
    }

    private static <T> RestResult<T> build(RestResultCode restResultCode, T data) {
        return build(restResultCode.getCode(), restResultCode.getDescription(), null, null, data);
    }

    private static <T> RestResult<T> build(Integer code, String title, String detail, String instance, T data) {
        RestResult<T> result = new RestResult<>();
        result.setCode(code);
        result.setTitle(title);
        result.setDetail(detail);
        result.setInstance(instance);
        result.setData(data);
        result.setTimestamp(Instant.now().toEpochMilli());
        return result;
    }

    public RestResult<T> page(int page, int size, int total) {
        RestResultPage restResultPage = new RestResultPage(page, size, total);
        this.setPage(restResultPage);
        return this;
    }

}
